#ifdef __GNUG__
#pragma implementation
#endif

#include "WindowBorder.h"

#include "Class.h"
#include "Buttons.h"
#include "Box.h"
#include "Window.h"
#include "TextItem.h"
#include "Menu.h"
#include "Env.h"
#include "OrdColl.h"
#include "Filler.h"
#include "Math.h"
#include "Look.h"

static u_short StretchBoxNEBits[]= {
#   include "StretchBoxNE.icon"
};
static u_short StretchBoxNWBits[]= {
#   include "StretchBoxNW.icon"
};
static u_short StretchBoxSEBits[]= {
#   include "StretchBoxSE.icon"
};
static u_short StretchBoxSWBits[]= {
#   include "StretchBoxSW.icon"
};

static SmartBitmap
	StretchBoxNW(8, StretchBoxNWBits),
	StretchBoxNE(8, StretchBoxNEBits),
	StretchBoxSW(8, StretchBoxSWBits),
	StretchBoxSE(8, StretchBoxSEBits);

//---- EtIconBorder --------------------------------------------------------------

class EtIconBorder: public WindowBorder {
	int border;
public:
	MetaDef(EtIconBorder);
	EtIconBorder(VObject *title, VObject *inner);
	Command *DoLeftButtonDownCommand(Point p, Token, int);
	void Draw(Rectangle);
	Metric GetMinSize();
	void SetOrigin(Point at);
	void SetExtent(Point e);
};

//---- WindowButton ------------------------------------------------------------

class EtWindowButton: public Button {
	int type;
public:
	MetaDef(EtWindowButton);
	EtWindowButton(int id, int i);
	Metric GetMinSize()
		{ return Metric(Point(28)); }
	void DrawInner(Rectangle, bool);
};

//---- WindowBorder ------------------------------------------------------------

class EtWindowBorder: public WindowBorder {
	Menu *menu;
	TextItem *ti;
	bool border;
public:
	MetaDef(EtWindowBorder);

	EtWindowBorder(bool fixed, bool b, VObject *title, VObject *inner, TextItem *ti= 0);
	~EtWindowBorder();
	void Draw(Rectangle);
	Metric GetMinSize();
	void SetOrigin(Point at);
	void SetExtent(Point e);
	Command *DoLeftButtonDownCommand(Point p, Token, int);
	Menu *GetMenu();
	void SetTitle(const char*);
};

//---- WindowButton ------------------------------------------------------------

NewMetaImpl0(EtWindowButton,Button);

EtWindowButton::EtWindowButton(int id, int i) : Button(id, 0)
{
	SetFlag(eVObjHFixed|eVObjVFixed);
	type= i;
}

void EtWindowButton::DrawInner(Rectangle, bool highlight)
{
	Rectangle r(contentRect);
	GrSetPenNormal();
	switch (type) {
	case 0:
		r= r.Inset(6);
		break;
	case 1:
		return;
	case 2:
		r= r.Inset(6);
		break;
	case 3:
		r= r.Inset(6);
		break;
	}
	r= r.Inset(3);
	r.origin.y-= 3;
	if (highlight)
		GrPaintRect(r, gHighlightColor);
	GrStrokeRect(r);
	Button::Draw(r);
}

//---- EtWindowBorder ----------------------------------------------------------

NewMetaImpl(EtWindowBorder,WindowBorder, (TP(menu)));

EtWindowBorder::EtWindowBorder(bool fix, bool b, VObject *title, VObject *inner,
				TextItem *tit) : WindowBorder(fix, title, inner)
{
	border= b;
	menu= 0;
	ti= tit;
}

EtWindowBorder::~EtWindowBorder()
{
	SafeDelete(menu);
}

void EtWindowBorder::SetTitle(const char *t)
{
	if (ti)
		ti->SetString(t);
	if (IsOpen()) {
		SetExtent(GetExtent());
		SetOrigin(GetOrigin());
		ForceRedraw();
	}
}

Menu *EtWindowBorder::GetMenu()
{
	if (menu == 0) {
		menu= new Menu("Window", FALSE);
		menu->AppendItems(
				"collapse",     cCOLLAPSE,
				"top",          cTOP,
				"bottom",       cBOTTOM,
				"redisplay    ",cREDISPLAY,
				0
		);
	}
	return menu;
}

Metric EtWindowBorder::GetMinSize()
{
	Point e= At(0)->GetMinSize().extent + 2*gPoint10;
	if (Size() > 1)
		e.y+= At(1)->GetMinSize().extent.y;
	return e;
}

void EtWindowBorder::SetOrigin(Point at)
{
	VObject::SetOrigin(at);
	at+= gPoint10;
	if (Size() > 1) {
		int y= At(1)->GetMinSize().extent.y;
		At(1)->SetOrigin(at);
		at.y+= y;
	}
	At(0)->SetOrigin(at);
}

void EtWindowBorder::SetExtent(Point e)
{
	VObject::SetExtent(e);
	e-= 2*gPoint10;
	if (Size() > 1) {
		int y= At(1)->GetMinSize().extent.y;
		At(1)->SetExtent(Point(e.x, y));
		e.y-= y;
	}
	At(0)->SetExtent(e);
}

void EtWindowBorder::Draw(Rectangle dr)
{
	//bool active= GetWindow()->IsActive();
	Rectangle ir(At(0)->contentRect);

	GrPaintRect(ir, gLook->backgroundColor);

	if (! ir.ContainsRect(dr)) {
		Rectangle rl[4];
		int n= Difference(rl, dr, ir);
		for (int i= 0; i < n; i++)
			GrPaintRect(rl[i], gLook->backgroundColor);
		
		if (border)
			GrStrokeRect(ir.Expand(gPoint1));
		Rectangle r= contentRect;
		GrSetPenNormal();
		GrSetPenSize(2);
		GrStrokeRect(r);
		GrSetPenSize(1);

		//if (GrHasColor() && active)
		//    GrPaintRect(tr, windowHighlightColor);
		//if (!GrHasColor() && active)
		//   GrPaintRect(tr, windowHighlightColor);
		
		if (!fixed) {
			GrPaintBitMap(Rectangle(r.NW()+gPoint2, 8), StretchBoxNW, ePatBlack);
			GrPaintBitMap(Rectangle(r.NE()+Point(-9,2), 8), StretchBoxNE, ePatBlack);
			GrPaintBitMap(Rectangle(r.SE()+Point(-9,-9), 8), StretchBoxSE, ePatBlack);
			GrPaintBitMap(Rectangle(r.SW()+Point(2,-9), 8), StretchBoxSW, ePatBlack);
		}
	}
	CompositeVObject::Draw(dr);
}

Command *EtWindowBorder::DoLeftButtonDownCommand(Point p, Token, int)
{
	Command *wm= gNoChanges;
	if (!At(0)->contentRect.ContainsPoint(p)) {
		Window *win= GetWindow();
		Rectangle r(contentRect);

		if (!fixed) {
			if (Rectangle(r.NW()+gPoint2, 8).ContainsPoint(p)
				|| Rectangle(r.NE()+Point(-9,2), 8).ContainsPoint(p)
				|| Rectangle(r.SE()+Point(-9,-9), 8).ContainsPoint(p)
				|| Rectangle(r.SW()+Point(2,-9), 8).ContainsPoint(p))
				wm= new VObjectStretcher(win, win->ScreenRect());
		}
		if (wm == gNoChanges)
			wm= new VObjectMover(win, win->ScreenRect(), gPoint1, eCrsMoveHand, 4);

		wm->SetFlag(eCmdFullScreen);
		wm->SetType(eCmdTypeNoChange);
	}
	return wm;
}

//---- EtIconBorder --------------------------------------------------------------

NewMetaImpl0(EtIconBorder,WindowBorder);

EtIconBorder::EtIconBorder(VObject *title, VObject *inner)
					: WindowBorder(TRUE, title, inner)
{
	border= 2;
}

Metric EtIconBorder::GetMinSize()
{
	Point e(64+2*border);
	Point m(At(1)->GetMinSize().extent+2*border);
	e.x= Math::Max(e.x, m.x);
	e.y+= m.y;
	return e;
}

void EtIconBorder::SetOrigin(Point at)
{
	VObject::SetOrigin(at);
	Rectangle r(contentRect);
	int h= At(1)->Height() + 2*border;

	r.extent.y-= h;
	At(0)->Align(r.origin, r.extent, (VObjAlign) (eVObjHCenter|eVObjVCenter));

	r.origin.y= r.extent.y;
	r.extent.y= h;
	At(1)->Align(r.origin, r.extent, (VObjAlign) (eVObjHCenter|eVObjVBottom));
}

void EtIconBorder::SetExtent(Point e)
{
	VObject::SetExtent(e);
	At(0)->CalcExtent();
	At(1)->CalcExtent();
}

void EtIconBorder::Draw(Rectangle r)
{
	GrGetPort()->StrokeRect(gInkBlack, 2, contentRect);
	CompositeVObject::Draw(r);
}

Command *EtIconBorder::DoLeftButtonDownCommand(Point, Token, int clicks)
{
	Window *win= GetWindow();
	if (clicks >= 2) {
		win->Iconize();
		return gNoChanges;
	}
	Command *wm= new VObjectMover(win, win->ScreenRect(), gPoint4,
								eCrsMoveHand, 4);
	wm->SetFlag(eCmdFullScreen);
	wm->SetType(eCmdTypeNoChange);
	return wm;
}

//---- entrypoint --------------------------------------------------------------

VObject *MakeEtWindowBorder(WindowType wt, VObject *in, char *title,
						bool blocked, bool fixed)
{
	TextItem *ti= 0;
	OrdCollection *col= new OrdCollection;

	switch (wt) {

	case eWinIcon: // Icon
		ti= new TextItem(cIdIconLabel, title);
		ti->SetFlag(eVObjHFixed);
		return new EtIconBorder(ti, in);

	case eWinPlain: // plain window ala Window
		return in;
		
	case eWinStandard:
		if (title == 0)
			title= "";
		col->Add(new EtWindowButton(cIdCloseBox, 0));
		col->Add(ti= new TextItem(cIdWindowTitle, title));
		col->Add(new EtWindowButton(cIdBottom, 3));
		return new EtWindowBorder(fixed, FALSE,
				new HBox(gPoint0, eVObjHGapExpand, col), in, ti);

	case eWinDialog:
		if (title || !fixed || !blocked) {
			if (!blocked)
				col->Add(new EtWindowButton(cIdCloseBox, 0));
			if (title) {
				col->Add(new Filler(gPoint0));
				col->Add(ti= new TextItem(cIdWindowTitle, title));
				col->Add(new Filler(gPoint0));
			}
			if (!blocked && !fixed)
				col->Add(new EtWindowButton(cIdBottom, 3));
			return new EtWindowBorder(fixed, TRUE,
				new HBox(gPoint0, eVObjHGapExpand, col), in, ti);
		}
		return new EtWindowBorder(fixed, TRUE, 0, in);
		
	default:
		return in;
	}
}

